package com.wlyuan.open.scanner.application.interceptor;

import com.baomidou.mybatisplus.extension.plugins.handler.DataPermissionHandler;
import com.wlyuan.open.scanner.application.annotation.DataScope;
import com.wlyuan.open.scanner.config.ScannerProperties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
import net.sf.jsqlparser.expression.operators.relational.InExpression;
import net.sf.jsqlparser.expression.operators.relational.ItemsList;
import net.sf.jsqlparser.schema.Column;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.stream.Collectors;

/**
 * @author lijing
 * @description
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class DataScopePermissionHandler implements DataPermissionHandler {
    private final ScannerProperties scannerProperties;

    @Override
    public Expression getSqlSegment(Expression where, String mappedStatementId) {
        try {
            String tenantIds = scannerProperties.getTenant();
            if (StringUtils.isBlank(tenantIds)) {
                return where;
            }

            Class<?> clazz = Class.forName(mappedStatementId.substring(0, mappedStatementId.lastIndexOf(".")));
            String methodName = mappedStatementId.substring(mappedStatementId.lastIndexOf(".") + 1);
            Method[] methods = clazz.getDeclaredMethods();
            for (Method method : methods) {
                DataScope annotation = method.getAnnotation(DataScope.class);
                if (ObjectUtils.isNotEmpty(annotation) && (method.getName().equals(methodName))) {
                    return dataScopeFilter(annotation.column(), annotation.alias(), tenantIds, where);
                }
            }
        } catch (ClassNotFoundException e) {
            logger.error("data scope permission error : {}", e.getMessage());
        }
        return where;
    }

    /**
     * 构建数据过滤条件
     *
     * @param column 列名
     * @param alias  表别名
     * @param ids    过滤id
     * @param where  where 条件
     * @return
     */
    private static Expression dataScopeFilter(String column, String alias, String ids, Expression where) {
        ItemsList itemsList = new ExpressionList(Arrays.asList(ids).stream().map(LongValue::new).collect(Collectors.toList()));
        InExpression inExpression = new InExpression(buildColumn(alias, column), itemsList);
        inExpression.setNot(true);
        return ObjectUtils.isNotEmpty(where) ? new AndExpression(where, inExpression) : inExpression;
    }

    /**
     * 构建过滤Column
     *
     * @param tableAlias 表别名
     * @param columnName 列名
     * @return
     */
    private static Column buildColumn(String tableAlias, String columnName) {
        if (StringUtils.isNotEmpty(tableAlias)) {
            columnName = tableAlias + "." + columnName;
        }
        return new Column(columnName);
    }
}
